home *** CD-ROM | disk | FTP | other *** search
/ Mac-Source 1994 July / Mac-Source_July_1994.iso / C and C++ / Utilities / Winter Shell 1.0d2 / Source / Libraries / WindowLib / WindowZoomLib.c < prev   
Encoding:
C/C++ Source or Header  |  1994-01-19  |  10.7 KB  |  341 lines  |  [TEXT/KAHL]

  1. /* functions for zooming windows and for saving and restoring window positions.
  2.     94/01/08 aih - moved WinCouldDrag to WindowPositionLib.c
  3.     93/12/16 aih - added dfltpos field to window structure
  4.     93/11/27 aih - split from WindowPositionLib.c */
  5.     
  6. #include <stdlib.h>
  7. #include <string.h>
  8. #include "ArchiveLib.h"
  9. #include "DrawLib.h"
  10. #include "FileLib.h"
  11. #include "MathLib.h"
  12. #include "MemoryLib.h"
  13. #include "RectangleLib.h"
  14. #include "ResourceConstantsLib.h"
  15. #include "ResourceLib.h"
  16. #include "ResourceTypeLib.h"
  17. #include "ScreenLib.h"
  18. #include "WindowLib.h"
  19.  
  20. /* Version of this library, which is used to determine if window data
  21.     written to a file with a different version of this library can be
  22.     used with the current version. */
  23. #define WIN_VERSION (3)
  24.  
  25. /* structure used to save and restore a window's size, position, and zoom
  26.     state */
  27. typedef struct {
  28.     Boolean    zoomed;    /* true if in zoomed state */
  29.     Rect        bounds;    /* window's user and standard states */
  30. } WindowStateType;
  31.  
  32. /* get the window's zoom state */
  33. void WinZoomState(WindowPtr window, WStateData *zoomState)
  34. {
  35.     require(WinHasZoom(window));
  36.     *zoomState = **(WStateData **) ((WindowPeek) window)->dataHandle;
  37. }
  38.  
  39. /* set the window's user and standard states */
  40. void WinZoomStateSet(WindowPtr window, const WStateData *zoomState)
  41. {
  42.     require(WinHasZoom(window));
  43.     **(WStateData **) ((WindowPeek) window)->dataHandle = *zoomState;
  44. }
  45.  
  46. /* initialize window's user state */
  47. void WinZoomReset(WindowPtr window)
  48. {
  49.     WStateData zoomState;
  50.     
  51.     if (WinHasZoom(window)) {
  52.         WinZoomState(window, &zoomState);
  53.         WinContentRect(window, &zoomState.userState);
  54.         WinZoomStateSet(window, &zoomState);
  55.     }
  56. }
  57.  
  58. /* true if the window is in the standard state (see IM-IV, p10) */
  59. static Boolean WinZoomed(WindowPtr window)
  60. {
  61.     WStateData zoomState;
  62.     Rect contentRect;
  63.     Boolean result = false;
  64.     
  65.     if (WinHasZoom(window)) {
  66.         WinZoomState(window, &zoomState);
  67.         WinContentRect(window, &contentRect);
  68.         result =
  69.             (abs(contentRect.top - zoomState.stdState.top) <= 7 &&
  70.              abs(contentRect.left - zoomState.stdState.left) <= 7 &&
  71.              abs(contentRect.bottom - zoomState.stdState.bottom) <= 7 &&
  72.              abs(contentRect.right - zoomState.stdState.right) <= 7);
  73.     }
  74.     return(result); 
  75. }
  76.  
  77. /* Prepare to zoom the window by calculating its standard state. This function
  78.     should be called after a mouseDown in the zoom box of the window, but before
  79.     TrackBox is called. This function should also be called just before
  80.     a window's state is restored from a saved file, in case the saved
  81.     state indicates that the window should be zoomed. */
  82. void WinZoomPrepare(WindowPtr window)
  83. {
  84.     short width, height;        /* window's preferred width and height */
  85.     Rect sizeRect;                /* window's minimum and maximum size */
  86.     Rect newRect;                /* maximum rectangle of a new window */
  87.     Rect contentRect;            /* window's content rectangle */    
  88.     WStateData zoomState;    /* window's zoom state */
  89.     
  90.     require(WinValid(window));
  91.     
  92.     /* use screen containing greatest portion of window */
  93.     ScreenSet(ScreenContainingWindow(window));
  94.     
  95.     /* adjust width and height to minimum and maximum size of window and
  96.         to maximum size of a window on the current screen */
  97.     WinNewRect(window, &newRect);
  98.     WinSizeRect(window, &sizeRect);
  99.     WinSizePreferred(window, &width, &height);
  100.     check(sizeRect.left <= RectWidth(&newRect));
  101.     check(sizeRect.top <= RectHeight(&newRect));
  102.     width = min(min(max(width, sizeRect.left), sizeRect.right), RectWidth(&newRect));
  103.     height = min(min(max(height, sizeRect.top), sizeRect.bottom), RectHeight(&newRect));
  104.  
  105.     /* set the zoom rectangle's size to the new width and height of the
  106.         window, and use the window's current position if the entire window
  107.         would be visible on the current screen */
  108.     WinZoomState(window, &zoomState);
  109.     WinContentRect(window, &contentRect);
  110.     zoomState.stdState.top = contentRect.top;
  111.     zoomState.stdState.left = contentRect.left;
  112.     zoomState.stdState.bottom = zoomState.stdState.top + height;
  113.     zoomState.stdState.right = zoomState.stdState.left + width;
  114.     if (! RectWithin(&zoomState.stdState, &newRect)) {
  115.         zoomState.stdState.top = newRect.top;
  116.         zoomState.stdState.left = newRect.left;
  117.         zoomState.stdState.bottom = zoomState.stdState.top + height;
  118.         zoomState.stdState.right = zoomState.stdState.left + width;
  119.     }
  120.     WinZoomStateSet(window, &zoomState);
  121. }
  122.  
  123. /* zoom the window */
  124. void WinZoom(WindowPtr window, short part)
  125. {
  126.     Rect oldPortRect, newPortRect;
  127.     Rect oldContent, newContent;
  128.     GrafPtr port = NULL;
  129.     
  130.     require(WinValid(window));
  131.     GetPort(&port);
  132.     SetPort(window);
  133.     WinPortRect(window, &oldPortRect);
  134.     WinContentRect(window, &oldContent);
  135.     ZoomWindow(window, part, false);
  136.     WinPortRect(window, &newPortRect);
  137.     WinContentRect(window, &newContent);
  138.     if (EqualPt(topLeft(oldContent), topLeft(newContent))) {
  139.         /* window didn't move */
  140.         InvalXorRect(&oldPortRect, &newPortRect);
  141.         if (WinHasGrow(window)) {
  142.             /* invalidate grow region */
  143.             oldPortRect.top = oldPortRect.bottom - 15;
  144.             oldPortRect.left = oldPortRect.right - 15;
  145.             newPortRect.top = newPortRect.bottom - 15;
  146.             newPortRect.left = newPortRect.left - 15;
  147.             EraseRect(&oldPortRect);
  148.             InvalRect(&oldPortRect);
  149.             EraseRect(&newPortRect);
  150.             InvalRect(&newPortRect);
  151.         }
  152.     }
  153.     else {
  154.         /* window moved */
  155.         EraseRect(&newPortRect);
  156.         InvalRect(&newPortRect);
  157.     }
  158.     SetPort(port);
  159.     ensure(WinValid(window));
  160. }
  161.  
  162. /*----------------------------------------------------------------------------*/
  163. /* saving and restoring a window's zoom state */
  164. /*----------------------------------------------------------------------------*/
  165.  
  166. /* true if window has been moved or resized */
  167. static Boolean WinMovedOrResized(WindowPtr window)
  168. {
  169.     Rect curpos, dfltpos;
  170.  
  171.     dfltpos = WinExtraPtr(window)->dfltpos;
  172.     WinPortRect(window, &curpos);
  173.     RectPortToGlobal(&curpos, window);
  174.     return(! EqualRect(&curpos, &dfltpos));
  175. }
  176.  
  177. /* get the window's state  */
  178. static void WinState(WindowPtr window, WindowStateType *state)
  179. {
  180.     require(WinValid(window));
  181.     memclr(state, sizeof(WindowStateType));
  182.     if (WinMovedOrResized(window))
  183.         WinContentRect(window, &state->bounds);
  184.     state->zoomed = WinZoomed(window);
  185. }
  186.  
  187. /* adjust the state so it's in accordance with HIN#6 */
  188. static void WinStateFix(WindowPtr window, WindowStateType *state)
  189. {
  190.     RgnHandle invisibleRgn;    /* region of rectangle that is invisible */
  191.     WindowStateType dflt;    /* window's default state */
  192.     Rect sizeRect;                /* window's minimum and maximum size */
  193.     Rect contentRect;            /* window's content rectangle */
  194.     
  195.     require(WinValid(window));
  196.     
  197.     /* use default rectangle if current rectangle isn't valid */
  198.     WinSizeRect(window, &sizeRect);
  199.     WinContentRect(window, &contentRect);
  200.     if (! RectValid(&state->bounds) ||
  201.          RectWidth(&state->bounds) < sizeRect.left ||
  202.          RectWidth(&state->bounds) > sizeRect.right ||
  203.          RectHeight(&state->bounds) < sizeRect.top ||
  204.          RectHeight(&state->bounds) > sizeRect.bottom)
  205.     {
  206.         state->bounds = contentRect;
  207.     }
  208.     else if (! WinCouldDrag(window, &state->bounds)) {
  209.         
  210.         /* window can't be dragged so use default position */
  211.         RectMove(&state->bounds, contentRect.left, contentRect.top);
  212.         
  213.         /* use default size if any part of the window would be invisible */
  214.         invisibleRgn = BeginRgn();
  215.         RectRgn(invisibleRgn, &state->bounds);
  216.         DiffRgn(invisibleRgn, GetGrayRgn(), invisibleRgn);
  217.         if (! EmptyRgn(invisibleRgn))
  218.             state->bounds = contentRect;
  219.         EndRgn(invisibleRgn);
  220.     }
  221. }
  222.  
  223. /* apply the state to the window */
  224. static void WinStateApply(WindowPtr window, WindowStateType *state)
  225. {
  226.     WStateData zoomState;
  227.     Rect oldSize, newSize;
  228.     short dh, dv;
  229.     
  230.     require(WinValid(window));
  231.     if (WinHasZoom(window)) {
  232.         WinZoomPrepare(window);
  233.         WinZoomState(window, &zoomState);
  234.         zoomState.userState = state->bounds;
  235.         if (state->zoomed)
  236.             state->bounds = zoomState.stdState;
  237.         WinZoomStateSet(window, &zoomState);
  238.     }
  239.     WinPortRect(window, &oldSize);
  240.     if (WinHasGrow(window) || WinHasZoom(window)) {
  241.         /* only resize if window's size can change; this guards against
  242.             invalid states and against having changes made to window sizes in
  243.             the resource file being overridden by old preferences files */
  244.         WinSize(window, RectWidth(&state->bounds), RectHeight(&state->bounds));
  245.     }
  246.     WinMove(window, state->bounds.left, state->bounds.top);
  247.     WinPortRect(window, &newSize);
  248.     WinResize(window, RectWidth(&newSize) - RectWidth(&oldSize),
  249.                             RectHeight(&newSize) - RectHeight(&oldSize));
  250.     ensure(WinValid(window));
  251.     ensure((WinHasZoom(window) && state->zoomed) ? WinZoomed(window) : true);
  252. }
  253.  
  254. /* remember the window's current position as the default position */
  255. void WinZoomRemember(WindowPtr window)
  256. {
  257.     Rect pos;
  258.  
  259.     WinPortRect(window, &pos);
  260.     RectPortToGlobal(&pos, window);
  261.     WinExtraPtr(window)->dfltpos = pos;
  262. }
  263.  
  264. /* Read the window's position, size, and zoom states from the resource
  265.     with the specified ID in the current resource file. The restored state
  266.     is adjusted to a reasonable size for the window and then applied to
  267.     the window. This function attempts to adhere to the guidelines in the
  268.     HIN and in IM-VI. */
  269. void WinZoomRead(WindowPtr window, short id)
  270. {
  271.     WindowStateType state;    /* archived state data */
  272.     size_t    size;                /* size of archived data */
  273.     long        version;            /* version of archived data */
  274.     
  275.     require(WinValid(window));
  276.     size = sizeof(WindowStateType);
  277.     version = WIN_VERSION;
  278.     ArchiveReadRes(RES_WPOS_TYPE, id, &state, &size, &version);
  279.     if (version != WIN_VERSION || size != sizeof(WindowStateType))
  280.         memclr(&state, sizeof(WindowStateType));
  281.     WinStateFix(window, &state);
  282.     WinStateApply(window, &state);
  283.     WinZoomRemember(window);
  284. }
  285.  
  286. /* Write the window's position, size, and zoom states to the resource
  287.     with the specified ID in the current resource file. The window's state
  288.     can later be restored with WinZoomRestore. */
  289. void WinZoomWrite(WindowPtr window, short id)
  290. {
  291.     WindowStateType state;
  292.     
  293.     require(WinValid(window));
  294.     if (WinMovedOrResized(window)) {
  295.         WinState(window, &state);
  296.         ArchiveWriteRes(RES_WPOS_TYPE, id, &state, sizeof(WindowStateType), WIN_VERSION);
  297.     }
  298. }
  299.  
  300. /* Read the window's state from the resource with the specified
  301.     ID in the specified file's resource fork. */
  302. void WinZoomRestore(WindowPtr window, FileType *fp, short id)
  303. {
  304.     volatile FileRefType    ref = FILE_CLOSED;
  305.  
  306.     TRY {
  307.         if (ResFileExists(fp)) {
  308.             ref = ResFileOpen(fp, fsRdPerm);
  309.             if (ResExists1(RES_WPOS_TYPE, id))
  310.                 WinZoomRead(window, id);
  311.         }
  312.         WinZoomRemember(window);
  313.     } CLEANUP {
  314.         ResFileClose(ref);
  315.     } ENDTRY;
  316. }
  317.  
  318. /* Save the window's current state if it differs from the default state. The
  319.     state is written to the resource fork of the specified file, and the
  320.     file's modification date is unchanged. */
  321. void WinZoomSave(WindowPtr window, FileType *fp, short id)
  322. {
  323.     CInfoPBRec pb;
  324.     volatile FileRefType ref = FILE_CLOSED;
  325.  
  326.     TRY {
  327.         if (WinMovedOrResized(window)) {
  328.             FileCatalog(fp, &pb);
  329.             if (! ResFileExists(fp))
  330.                 ResFileCreate(fp);
  331.             ref = ResFileOpen(fp, fsWrPerm); 
  332.             WinZoomWrite(window, id);
  333.             ResFileClose(ref);
  334.             ref = FILE_CLOSED;
  335.             FileCatalogSet(fp, &pb);
  336.         }
  337.     } CATCH {
  338.         ResFileClose(ref);
  339.     } ENDTRY;
  340. }
  341.